//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package project_doc_api_serv

import (
	"context"
	"strings"
	"time"

	"atomgit.com/openlinksaas-org/api-server/api_common"
	"atomgit.com/openlinksaas-org/api-server/dao"
	"atomgit.com/openlinksaas-org/api-server/dao/idea_dao"
	"atomgit.com/openlinksaas-org/api-server/dao/project_doc_dao"
	"atomgit.com/openlinksaas-org/api-server/dao/project_entry_dao"
	"atomgit.com/openlinksaas-org/api-server/utils"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/project_doc_api"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/project_entry_api"
	"github.com/google/uuid"
	"go.mongodb.org/mongo-driver/mongo"
)

// 创建文档
func (apiImpl *ProjectDocApiImpl) CreateDoc(ctx context.Context, req *project_doc_api.CreateDocRequest) (*project_doc_api.CreateDocResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_doc_api.CreateDocResponse{
			Code:   project_doc_api.CreateDocResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	//检查权限
	projectItem, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_doc_api.CreateDocResponse{
			Code:   project_doc_api.CreateDocResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_doc_api.CreateDocResponse{
			Code:   project_doc_api.CreateDocResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_doc_api.CreateDocResponse{
			Code:   project_doc_api.CreateDocResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	docId := uuid.NewString()

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = project_doc_dao.DocContentDao.Insert(sessCtx, &project_doc_dao.DocContentDbItem{
			DocId:   docId,
			Content: req.BaseInfo.Content,
		})
		if err != nil {
			return nil, err
		}
		return &project_doc_api.CreateDocResponse{
			Code:  project_doc_api.CreateDocResponse_CODE_OK,
			DocId: docId,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	return ret.(*project_doc_api.CreateDocResponse), nil
}

// 更新文档内容
func (apiImpl *ProjectDocApiImpl) UpdateDocContent(ctx context.Context, req *project_doc_api.UpdateDocContentRequest) (*project_doc_api.UpdateDocContentResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_doc_api.UpdateDocContentResponse{
			Code:   project_doc_api.UpdateDocContentResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	//检查权限
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_doc_api.UpdateDocContentResponse{
			Code:   project_doc_api.UpdateDocContentResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_doc_api.UpdateDocContentResponse{
			Code:   project_doc_api.UpdateDocContentResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_doc_api.UpdateDocContentResponse{
			Code:   project_doc_api.UpdateDocContentResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	entryItem, err := project_entry_dao.EntryDao.Get(ctx, req.DocId, req.ProjectId)
	if err != nil {
		return &project_doc_api.UpdateDocContentResponse{
			Code:   project_doc_api.UpdateDocContentResponse_CODE_NO_DOC,
			ErrMsg: "文档不存在",
		}, nil
	}
	if entryItem.EntryType != uint32(project_entry_api.ENTRY_TYPE_ENTRY_TYPE_DOC) {
		return &project_doc_api.UpdateDocContentResponse{
			Code:   project_doc_api.UpdateDocContentResponse_CODE_NO_DOC,
			ErrMsg: "文档不存在",
		}, nil
	}

	hasUpdatePerm := api_common.CheckEntryCanUpdate(sessionItem, projectItem, roleItem, entryItem)

	if !hasUpdatePerm {
		return &project_doc_api.UpdateDocContentResponse{
			Code:   project_doc_api.UpdateDocContentResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	//检查编辑状态
	editInfo, ok := dao.CacheDao.GetEntryEdit(ctx, req.DocId)
	if !ok {
		return &project_doc_api.UpdateDocContentResponse{
			Code:   project_doc_api.UpdateDocContentResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	if editInfo.ProjectId != req.ProjectId || editInfo.EntryId != req.DocId || editInfo.EditUserId != sessionItem.UserId {
		return &project_doc_api.UpdateDocContentResponse{
			Code:   project_doc_api.UpdateDocContentResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	docContentItem, err := project_doc_dao.DocContentDao.Get(ctx, req.DocId)
	if err != nil {
		return nil, err
	}
	//不保存重复内容
	if req.Content == docContentItem.Content {
		dao.CacheDao.RemoveEntryEdit(ctx, req.DocId)
		return &project_doc_api.UpdateDocContentResponse{
			Code: project_doc_api.UpdateDocContentResponse_CODE_OK,
		}, nil
	}

	nowTime := time.Now().UnixNano() / 1e6
	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = project_doc_dao.DocContentDao.Update(sessCtx, req.DocId, req.Content)
		if err != nil {
			return nil, err
		}
		err = project_entry_dao.EntryDao.SetUpdateInfo(sessCtx, req.DocId, req.ProjectId, sessionItem.UserId, nowTime)
		if err != nil {
			return nil, err
		}

		return &project_doc_api.UpdateDocContentResponse{
			Code: project_doc_api.UpdateDocContentResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}

	return ret.(*project_doc_api.UpdateDocContentResponse), nil
}

// 获取文档
func (apiImpl *ProjectDocApiImpl) GetDoc(ctx context.Context, req *project_doc_api.GetDocRequest) (*project_doc_api.GetDocResponse, error) {
	emptyDoc := &project_doc_api.Doc{
		BaseInfo: &project_doc_api.BaseDoc{},
	}
	emptyKeywordList := []string{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_doc_api.GetDocResponse{
			Code:            project_doc_api.GetDocResponse_CODE_WRONG_SESSION,
			ErrMsg:          "会话不存在",
			Doc:             emptyDoc,
			IdeaKeywordList: emptyKeywordList,
		}, nil
	}
	//检查权限
	_, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_doc_api.GetDocResponse{
			Code:            project_doc_api.GetDocResponse_CODE_NO_PROJECT,
			ErrMsg:          "项目不存在",
			Doc:             emptyDoc,
			IdeaKeywordList: emptyKeywordList,
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_doc_api.GetDocResponse{
			Code:            project_doc_api.GetDocResponse_CODE_NO_PERMISSION,
			ErrMsg:          "没有权限",
			Doc:             emptyDoc,
			IdeaKeywordList: emptyKeywordList,
		}, nil
	} else if err != nil {
		return nil, err
	}

	contentItem, err := project_doc_dao.DocContentDao.Get(ctx, req.DocId)
	if err != nil {
		return &project_doc_api.GetDocResponse{
			Code:            project_doc_api.GetDocResponse_CODE_NO_DOC,
			ErrMsg:          "文档不存在",
			Doc:             emptyDoc,
			IdeaKeywordList: emptyKeywordList,
		}, nil
	}

	allKeywordList, err := idea_dao.IdeaDao.ListAllKeyword(ctx, req.ProjectId)
	if err != nil {
		return nil, err
	}

	keywordList := []string{}
	content := strings.ToLower(contentItem.Content)
	for _, kw := range allKeywordList {
		if strings.Contains(content, strings.ToLower(kw)) {
			keywordList = append(keywordList, kw)
		}
	}

	return &project_doc_api.GetDocResponse{
		Code: project_doc_api.GetDocResponse_CODE_OK,
		Doc: &project_doc_api.Doc{
			DocId: contentItem.DocId,
			BaseInfo: &project_doc_api.BaseDoc{
				Content: contentItem.Content,
			},
		},
		IdeaKeywordList: keywordList,
	}, nil
}

// 开始更新文档内容
func (apiImpl *ProjectDocApiImpl) StartUpdateDoc(ctx context.Context, req *project_doc_api.StartUpdateDocRequest) (*project_doc_api.StartUpdateDocResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_doc_api.StartUpdateDocResponse{
			Code:   project_doc_api.StartUpdateDocResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	//检查权限
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_doc_api.StartUpdateDocResponse{
			Code:   project_doc_api.StartUpdateDocResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_doc_api.StartUpdateDocResponse{
			Code:   project_doc_api.StartUpdateDocResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}

	entryItem, err := project_entry_dao.EntryDao.Get(ctx, req.DocId, req.ProjectId)
	if err != nil {
		return &project_doc_api.StartUpdateDocResponse{
			Code:   project_doc_api.StartUpdateDocResponse_CODE_NO_DOC,
			ErrMsg: "文档不存在",
		}, nil
	}
	if entryItem.EntryType != uint32(project_entry_api.ENTRY_TYPE_ENTRY_TYPE_DOC) {
		return &project_doc_api.StartUpdateDocResponse{
			Code:   project_doc_api.StartUpdateDocResponse_CODE_NO_DOC,
			ErrMsg: "文档不存在",
		}, nil
	}

	canUpdate := api_common.CheckEntryCanUpdate(sessionItem, projectItem, roleItem, entryItem)

	if !canUpdate {
		return &project_doc_api.StartUpdateDocResponse{
			Code:   project_doc_api.StartUpdateDocResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	//检查是否有其他人在编辑

	editInfo, ok := dao.CacheDao.GetEntryEdit(ctx, req.DocId)
	if ok {
		if editInfo.ProjectId != req.ProjectId || editInfo.EditUserId != sessionItem.UserId {
			return &project_doc_api.StartUpdateDocResponse{
				Code:   project_doc_api.StartUpdateDocResponse_CODE_NO_PERMISSION, //FIXME
				ErrMsg: "没有权限",
			}, nil
		}
	}

	//创建cache对象
	err = dao.CacheDao.SetEntryEdit(ctx, &dao.EntryEditDbItem{
		ProjectId:  req.ProjectId,
		EntryId:    req.DocId,
		EditUserId: sessionItem.UserId,
	})
	if err != nil {
		return nil, err
	}
	return &project_doc_api.StartUpdateDocResponse{
		Code: project_doc_api.StartUpdateDocResponse_CODE_OK,
	}, nil
}

// 持续更新文档内容(心跳)
func (apiImpl *ProjectDocApiImpl) KeepUpdateDoc(ctx context.Context, req *project_doc_api.KeepUpdateDocRequest) (*project_doc_api.KeepUpdateDocResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_doc_api.KeepUpdateDocResponse{
			Code:       project_doc_api.KeepUpdateDocResponse_CODE_WRONG_SESSION,
			ErrMsg:     "会话不存在",
			KeepUpdate: false,
		}, nil
	}
	editInfo, ok := dao.CacheDao.GetEntryEdit(ctx, req.DocId)
	if !ok {
		return &project_doc_api.KeepUpdateDocResponse{
			Code:       project_doc_api.KeepUpdateDocResponse_CODE_NO_PERMISSION,
			ErrMsg:     "没有权限",
			KeepUpdate: false,
		}, nil
	}
	if editInfo.EditUserId != sessionItem.UserId {
		return &project_doc_api.KeepUpdateDocResponse{
			Code:       project_doc_api.KeepUpdateDocResponse_CODE_NO_PERMISSION,
			ErrMsg:     "没有权限",
			KeepUpdate: false,
		}, nil
	}
	dao.CacheDao.KeepEntryEdit(ctx, req.DocId)
	return &project_doc_api.KeepUpdateDocResponse{
		Code:       project_doc_api.KeepUpdateDocResponse_CODE_OK,
		KeepUpdate: true,
	}, nil
}

func (apiImpl *ProjectDocApiImpl) EndUpdateDoc(ctx context.Context, req *project_doc_api.EndUpdateDocRequest) (*project_doc_api.EndUpdateDocResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_doc_api.EndUpdateDocResponse{
			Code:   project_doc_api.EndUpdateDocResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	editInfo, ok := dao.CacheDao.GetEntryEdit(ctx, req.DocId)
	if !ok {
		return &project_doc_api.EndUpdateDocResponse{
			Code: project_doc_api.EndUpdateDocResponse_CODE_OK,
		}, nil
	}

	if editInfo.EditUserId != sessionItem.UserId {
		return &project_doc_api.EndUpdateDocResponse{
			Code:   project_doc_api.EndUpdateDocResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	dao.CacheDao.RemoveEntryEdit(ctx, req.DocId)
	return &project_doc_api.EndUpdateDocResponse{
		Code: project_doc_api.EndUpdateDocResponse_CODE_OK,
	}, nil
}
